package com.spark.sniffer.plugin.plugins.interceptor;

import java.lang.reflect.Method;

import com.spark.sniffer.logging.api.Logger;
import com.spark.sniffer.logging.api.LoggerFactory;
import com.spark.sniffer.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import com.spark.sniffer.plugin.interceptor.enhance.MethodInterceptResult;
import com.spark.sniffer.tracing.Span;
import com.spark.sniffer.tracing.TraceId;
import com.spark.sniffer.tracing.TracingContext;

public class MqSubInterceptor implements InstanceMethodsAroundInterceptor {

    private static final Logger log = LoggerFactory.getLogger(MqSubInterceptor.class);

    @Override
    public void beforeMethod(Object instance, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
        MethodInterceptResult result) throws Throwable {
        // 如果mq消息中不携带traceid，则自产生一个
        TraceId.putToContext(TracingContext.getContext().getPassThroughMap() != null
            && TracingContext.getContext().getPassThroughMap().containsKey(TraceId.KEY)
                ? TracingContext.getContext().getPassThroughMap().get(TraceId.KEY) : TraceId.generate());
        TracingContext.getContext().entrance(Span.Type.MQConsumer,
            method.getDeclaringClass().getSimpleName() + "." + method.getName());
    }

    @Override
    public Object afterMethod(Object instance, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
        Object ret) throws Throwable {
        try {
            TracingContext.getContext().stopEntrance(Span.DEFAULT_CODE);
            printCallStack();
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            // DO remember this!!!
            TracingContext.removeContext();
        }

        return ret;
    }

    @Override
    public void handleMethodException(Object instance, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
        Throwable t) {
        TracingContext.getContext().stopEntrance(Span.ERR_CODE);
    }

    private void printCallStack() {
        Span entranceSpan = TracingContext.getContext().getEntrance();
        if (entranceSpan == null) {
            return;
        }
        log.info("tid={}, consumer={}, code={}, ts={}, trace=[{}], pass=[{}]", TracingContext.getContext().getTraceId(),
            entranceSpan.getName(), entranceSpan.getCode(), entranceSpan.getDuration(),
            TracingContext.getContext().callstack2string(), TracingContext.getContext().passThrough2string());
    }
}
